package org.study.sync;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.*;

import java.io.Serializable;
import java.util.concurrent.*;

/**
 * https://mp.weixin.qq.com/s/iDvrRL-Lxreluj8J7KtR7Q
 *
 * @author Administrator
 * @date 2021-10-22
 */
public class InterfaceAsync {
    public static void main(String[] args) {
        MyFutureTask myFutureTask = new MyFutureTask();
        long begin = System.currentTimeMillis();
        UserBehaviorDataDTO userBehaviorDataDTO = myFutureTask.getUserAggregatedResult(1L);
        System.out.println("总耗时：" + ((System.currentTimeMillis() - begin) / 1000) + " 秒");
        System.out.println(userBehaviorDataDTO);
    }
}

class MyFutureTask {
    // 核心线程 8 最大线程 20 保活时间30s 存储队列 10 有守护线程 拒绝策略:将超负荷任务回退到调用者
    private static ExecutorService executor0 = new ThreadPoolExecutor(8, 20,
            30L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10),
            new ThreadFactoryBuilder().setNameFormat("MyFutureTask-Thread-%d").setDaemon(true).build(),
            new ThreadPoolExecutor.CallerRunsPolicy());
    ExecutorService executor = Executors.newFixedThreadPool(6);
    ExecutorService executor2 = Executors.newCachedThreadPool();
    ExecutorService executor3 = Executors.newSingleThreadExecutor();
    ExecutorService executor4 = Executors.newScheduledThreadPool(1);

    public UserBehaviorDataDTO getUserAggregatedResult(final Long userId) {
        UserService userService = new UserService();
        System.out.println("MyFutureTask 的线程：" + Thread.currentThread());
        long fansCount = 0, msgCount = 0, collectCount = 0, followCount = 0, redBagCount = 0, couponCount = 0;
        /*fansCount = userService.countFansCountByUserId(userId);
        msgCount = userService.countMsgCountByUserId(userId);
        collectCount = userService.countCollectCountByUserId(userId);
        followCount = userService.countFollowCountByUserId(userId);
        redBagCount = userService.countRedBagCountByUserId(userId);
        couponCount = userService.countCouponCountByUserId(userId);*/
        Future<Long> fansCountFT = executor.submit(() -> userService.countFansCountByUserId(userId));
        Future<Long> msgCountFT = executor.submit(() -> userService.countMsgCountByUserId(userId));
        Future<Long> collectCountFT = executor.submit(() -> userService.countCollectCountByUserId(userId));
        Future<Long> followCountFT = executor.submit(() -> userService.countFollowCountByUserId(userId));
        Future<Long> redBagCountFT = executor.submit(() -> userService.countRedBagCountByUserId(userId));
        Future<Long> couponCountFT = executor.submit(() -> userService.countCouponCountByUserId(userId));

        try {// get() 阻塞
            fansCount = fansCountFT.get();
            msgCount = msgCountFT.get();
            collectCount = collectCountFT.get();
            followCount = followCountFT.get();
            redBagCount = redBagCountFT.get();
            couponCount = couponCountFT.get();
        } catch (InterruptedException | ExecutionException e) {
            //e.printStackTrace();
            System.err.println(">>>>>>聚合查询用户聚合信息异常:" + e + "<<<<<<<<<");
        }

        /*try {// get(long timeout, TimeUnit unit) 阻塞
            fansCount = fansCountFT.get(1, TimeUnit.SECONDS);
            msgCount = msgCountFT.get(1, TimeUnit.SECONDS);
            collectCount = collectCountFT.get(1, TimeUnit.SECONDS);
            followCount = followCountFT.get(1, TimeUnit.SECONDS);
            redBagCount = redBagCountFT.get(1, TimeUnit.SECONDS);
            couponCount = couponCountFT.get(1, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException e) {
            //e.printStackTrace();
            log.error("聚合查询信息异常：" + e);
        } catch (TimeoutException e) {
            log.error("聚合查询信息超时：" + e);
        }*/

        UserBehaviorDataDTO userBehaviorData = UserBehaviorDataDTO.builder()
                .fansCount(fansCount)
                .msgCount(msgCount)
                .collectCount(collectCount)
                .followCount(followCount)
                .redBagCount(redBagCount)
                .couponCount(couponCount).build();
        return userBehaviorData;
    }
}

class UserService {
    public long countFansCountByUserId(Long userId) {
        this.printLog(Thread.currentThread().getName(), userId, "FansCount", 2);
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 520;
    }

    public long countMsgCountByUserId(Long userId) {
        this.printLog(Thread.currentThread().getName(), userId, "MsgCount", 1);
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 618;
    }

    public long countCollectCountByUserId(Long userId) {
        this.printLog(Thread.currentThread().getName(), userId, "CollectCount", 5);
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 6664;
    }

    public long countFollowCountByUserId(Long userId) {
        this.printLog(Thread.currentThread().getName(), userId, "FollowCount", 3);
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 1024;
    }

    public long countRedBagCountByUserId(Long userId) {
        this.printLog(Thread.currentThread().getName(), userId, "RedBagCount", 4);
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 99;
    }

    public long countCouponCountByUserId(Long userId) {
        this.printLog(Thread.currentThread().getName(), userId, "CouponCount", 6);
        try {
            TimeUnit.SECONDS.sleep(6);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 66;
    }

    private void printLog(String currentThreadName, long userId, String bizName, long timeout) {
        System.err.println("当前线程 " + currentThreadName + "，获取userId=" + userId + " 的 " + bizName + "，睡眠 " + timeout + "s");
    }
}

@Data
@Builder
@ToString
class UserBehaviorDataDTO implements Serializable {
    private static final long serialVersionUID = -1334196672113960121L;

    private Long fansCount;
    private Long msgCount;
    private Long collectCount;
    private Long followCount;
    private Long redBagCount;
    private Long couponCount;
}